﻿namespace MefContrib.Models.Provider
{
    using System;
    using System.ComponentModel.Composition.Primitives;
    using System.Reflection;
    using MefContrib.Models.Provider.Validation;

    /// <summary>
    /// An immutable <see cref="ComposablePartCatalog"/> created from an <see cref="DefinitionProvider"/>.
    /// </summary>
    /// <typeparam name="TProvider">The type of a class which implements the <see cref="DefinitionProvider"/> interface.</typeparam>
    public class DefinitionProviderPartCatalog<TProvider> : DefinitionProviderPartCatalog where TProvider : DefinitionProvider
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DefinitionProviderPartCatalog{TProviderType}"/> class, using
        /// the provider specified by the <typeparamref name="TProvider"/> type and the values in the
        /// <paramref name="parameters"/> collection parameter.
        /// </summary>
        /// <param name="parameters">The parameters used to initialize the provider.</param>
        public DefinitionProviderPartCatalog(params object[] parameters)
        {
            parameters =
                parameters ?? new object[] { null };

            this.Provider =
                (TProvider)Activator.CreateInstance(typeof(TProvider), parameters);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DefinitionProviderPartCatalog{TProviderType}"/> class, using
        /// the specified <see cref="DefinitionProvider"/> instance.
        /// </summary>
        /// <param name="provider">An <see cref="DefinitionProvider"/> instance.</param>
        /// <exception cref="ArgumentNullException">The specified value for the provider was null.</exception>
        /// <exception cref="InvalidCastException">The type of the specified provider instance did not match the type specified by the generic parameter <typeparamref name="TProviderType"/> of the catalog.</exception>
        public DefinitionProviderPartCatalog(DefinitionProvider provider)
        {
            provider
                .Require("provider")
                .NotNull()
                .IsOfType(typeof(TProvider));

            this.Provider = provider;
        }
    }
}